package com.watson.juc.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @author watson
 * @date 2021/8/2 11:50
 * @Description: TODO
 **/
public class LazyMan {
    private static boolean qinjiang = false;

    private LazyMan() {
        synchronized (LazyMan.class) {
//            if (lazyMan != null) {
//                throw new RuntimeException("不要试图使用反射破坏异常,如果两个对象都通过反射获取，破解");
//            }


            if (qinjiang == false) {
                qinjiang = true;
            } else {
                throw new RuntimeException("不要试图使用反射破坏异常,如果两个对象都通过反射获取,预防，反射设置参数，破解");
            }
        }
//        System.out.println(Thread.currentThread().getName() + "OK");
    }

    private static LazyMan lazyMan;

    public static LazyMan getInstance() {
//        if (lazyMan == null) {
//            lazyMan = new LazyMan();
//        }
//
        //双重检测锁
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();
                    //1.分配内存空间
                    //2.执行构造方法，初始化对象
                    //3.把这个对象指向这个空间

                    //可能指令重排
                    // 123  132
                    //同时2线程：
                    //          判空返回时，lazyMan还没有完成构造
                }
            }
        }
        return lazyMan;
    }

    //多线程并发，需要加锁，双重检测锁
    public static void main(String[] args) throws Exception, IllegalAccessException, InvocationTargetException, InstantiationException {
//        for (int i = 0; i < 10; i++) {
//            new Thread(() -> {
//                LazyMan.getInstance();
//            }).start();
//        }
        LazyMan instance = LazyMan.getInstance();

        // 修改私有字段
        Field qinjiang = LazyMan.class.getDeclaredField("qinjiang");
        //无视私有，公有使用
        qinjiang.setAccessible(true);
        qinjiang.set(instance, false);

        //无参构造器
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        //无视私有，公有使用
        declaredConstructor.setAccessible(true);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance);
        System.out.println(instance2);

    }
}
